/**
 * 1. 实现state - 构建函数
 * 2. 实现setState更新 - 1）在render里面做重新渲染节点 2）绑定事件 3）setState方法 - 深拷贝合并，并渲染
 *  3. 跑起来react 教程代码
 *  思考：目前存在的问题，每次更新都是root的更新
 */

const RENDER_TO_DOM = Symbol("render to dom");
// 添加html元素
class ElementWrapper {
  constructor(tag) {
    this.root = document.createElement(tag);
  }

  setAttribute(name, value) {
    // [\s\S]+ 表示所有字符
    if (name.match(/^on([\s\S]+)$/)) {
      this.root.addEventListener(
        RegExp.$1.replace(/^[\s\S]/, (c) => c.toLowerCase()),
        value
      );
    } else if(name === 'className') {
      // 处理class
      this.root.setAttribute('class', value);
    }else {
      this.root.setAttribute(name, value);
    }
  }

  appendChild(component) {
    let range = document.createRange();
    range.setStart(this.root, this.root.childNodes.length);
    range.setEnd(this.root, this.root.childNodes.length);
    range.deleteContents();
    component[RENDER_TO_DOM](range);
  }

  [RENDER_TO_DOM](range) {
    // 使用range API 删除，再插入节点
    range.deleteContents();
    range.insertNode(this.root);
  }
}

// 添加文本节点
class TextWrapper {
  constructor(content) {
    this.root = document.createTextNode(content);
  }

  [RENDER_TO_DOM](range) {
    // 使用range API 删除，再插入节点
    range.deleteContents();
    range.insertNode(this.root);
  }
}

// 添加组件
export class Component {
  constructor() {
    // 初始化属性
    this.props = Object.create(null);
    this.children = [];
    this._root = null;
    this._range = null;
  }

  setAttribute(name, value) {
    this.props[name] = value;
  }

  appendChild(component) {
    this.children.push(component);
  }

  // 2. 使用symbol实现私有方法
  [RENDER_TO_DOM](range) {
    this._range = range;
    this.render()[RENDER_TO_DOM](range);
  }
  rerender() {
    // 修改bug之前
    // this._range.deleteContents();
    // this[RENDER_TO_DOM](this._range);

    // 重绘 - 修复range bug- 直接删除当range为空，如果有相邻的内容，就会被吞并，解决：先插入 再删除
    // 修改bug之后
    let oldRange = this._range; // 保存旧的range
    
    let range = document.createRange();
    range.setStart(oldRange.startContainer, oldRange.startOffset);
    range.setEnd(oldRange.startContainer, oldRange.startOffset);
    this[RENDER_TO_DOM](range);

    // 将旧的range插到内容之后
    oldRange.setStart(range.endContainer, range.endOffset);
    oldRange.deleteContents();
  }
  // 实现对象合并，并渲染
  setState(newState) {
    if (this.state === null || typeof this.state !== "object") {
      this.state = newState;
      this.rerender();
      return;
    }
    // 深拷贝合并
    let merge = (oldState, newState) => {
      for (let p in newState) {
        if (oldState[p] === null || typeof oldState[p] !== "object") {
          oldState[p] = newState[p];
        } else {
          merge(oldState[p], newState[p]);
        }
      }
    };
    merge(this.state, newState);
    this.rerender();
  }
}

// 创建dom节点
export function createElement(tag, attrbutes, ...children) {
  let e = null;
  if (typeof tag === "string") {
    e = new ElementWrapper(tag);
  } else {
    e = new tag();
  }

  for (let p in attrbutes) {
    e.setAttribute(p, attrbutes[p]);
  }
  let insertChildren = (children) => {
    for (let child of children) {
      if (typeof child === "string") {
        child = new TextWrapper(child);
      }
      if (child === null) {
        // 处理null 节点，不然会报错
        continue;
      }
      if (typeof child === "object" && child instanceof Array) {
        insertChildren(child);
      } else {
        e.appendChild(child);
      }
    }
  };
  insertChildren(children);

  return e;
}

export function render(component, parentElement) {
  // 创建range
  let range = document.createRange();
  // 0 parentElement 的子节点 的开始 ， length 到最后子节点
  range.setStart(parentElement, 0);
  range.setEnd(parentElement, parentElement.childNodes.length);
  range.deleteContents();
  component[RENDER_TO_DOM](range);
}
